package com.xy.biz.uc.domain.bo;

import com.xy.lang.domain.treeing.Tree;
import com.xy.lang.domain.treeing.TreeNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zsp
 * @date 2020-8-19
 */
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class ResourceBO {

	/**
	 * 类型 - 菜单
	 */
	public final static int TYPE_MENU = 1;
	/**
	 * 类型 - 功能
	 */
	public final static int TYPE_FUNCTION = 2;
	/**
	 * 状态 - 未启用
	 */
	public final static int STATUS_DISABLE = 0;
	/**
	 * 状态 - 启用
	 */
	public final static int STATUS_ENABLE = 1;

	/**
	 * 资源Id
	 */
	private Long resourceId;
	/**
	 * 资源编码
	 */
	private String resourceCode;
	/**
	 * 名称
	 */
	private String name;
	/**
	 * 模块
	 */
	private String module;
	/**
	 * 分组
	 */
	private String groups;
	/**
	 * 描述
	 */
	private String memo;
	/**
	 * 类型：1-菜单，2-功能
	 */
	private Integer type;
	/**
	 * 是否是系统管理功能：0-否，1-是
	 */
	private Boolean adminFlag;
	/**
	 * 状态：状态：0-未启用（隐藏），1-启用（显示）
	 */
	private Integer status;
	/**
	 * 应用编码
	 */
	private Integer applicationCode;
	/**
	 * 上级资源Id
	 */
	private Long parentResourceId;
	/**
	 * 排序号
	 */
	private Integer sequence;
	/**
	 * 路径
	 */
	private String path;
	/**
	 * 图标
	 */
	private String icon;
	/**
	 * 创建时间
	 */
	private LocalDateTime createTime;
	/**
	 * 更新时间
	 */
	private LocalDateTime updateTime;

	/**
	 * 上级资源
	 */
	private ResourceBO parentResource;
	/**
	 * 下级资源集合
	 */
	private List<ResourceBO> children;

	/**
	 * 构建资源的树
	 *
	 * @param collection
	 * @return
	 */
	public static List<TreeNode<ResourceBO>> buildTree(Collection<ResourceBO> collection) {
		if(!CollectionUtils.isEmpty(collection)) {
			List<ResourceBO> list = new ArrayList<>(collection);
			list.sort(Comparator.comparing(ResourceBO::getResourceId));
			return Tree.buildTree(list,
					ResourceBO::getResourceId,
					ResourceBO::getParentResourceId,
					e -> e == 0);
		}
		return Collections.emptyList();
	}

	/**
	 * 访问资源树
	 *
	 * @param collection
	 * @param action
	 */
	public static void visitTree(Collection<ResourceBO> collection,
								 Consumer<ResourceBO> action) {
		Objects.requireNonNull(action);
		if(!CollectionUtils.isEmpty(collection)) {
			List<TreeNode<ResourceBO>> treeNodeList = buildTree(collection);
			Tree.preorderDepthFirstVisit(treeNodeList,
					e -> {
						action.accept(e.getValue());
					});
		}
	}

	/**
	 * 访问资源树
	 *
	 * @param collection
	 * @param action
	 * @param childrenAction
	 * @param <R>
	 * @return
	 */
	public static <R> List<R> visitTree(Collection<ResourceBO> collection,
										Function<ResourceBO, R> action,
										BiConsumer<R, List<ResourceBO>> childrenAction) {
		Objects.requireNonNull(action);
		Objects.requireNonNull(childrenAction);
		if(!CollectionUtils.isEmpty(collection)) {
			List<TreeNode<ResourceBO>> treeNodeList = buildTree(collection);
			List<R> list = new ArrayList<>();
			Tree.preorderDepthFirstVisit(treeNodeList,
					e -> {
						R r = action.apply(e.getValue());
						if(e.isRoot()) {
							list.add(r);
						}
						if(e.hasChild()) {
							childrenAction.accept(r,
									e.getChildren().stream().map(TreeNode::getValue).collect(Collectors.toList()));
						}
					});
			return list;
		}
		return Collections.emptyList();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		ResourceBO that = (ResourceBO) o;
		return resourceId.equals(that.resourceId);
	}

	@Override
	public int hashCode() {
		return Objects.hash(resourceId);
	}

}
